dojo.provide("dojox.av._Media");

dojo.declare("dojox.av._Media", null, {
	// summary:
	//		Used as a mixin for dojox and AIR media
	//	description:
	//		Calculates the current status of the playing media and fires
	//		the appropriate events.
	//
	mediaUrl:"",
	//
	// initialVolume: Float?
	//		The initial volume setting of the player. Acccepts between 0 and 1.
	initialVolume:1,
	//
	//  autoPlay:Boolean?
	//		Whether the video automatically plays on load or not.
	autoPlay: false,
	//
	//	bufferTime: Number?
	//		Time in milliseconds that the video should be loaded before it will 
	//		play. May pause and resume to build up buffer. Prevents stuttering.
	//	Note:
	//		Older FLVs, without a duration, cannot be buffered.
	bufferTime: 2000,
	//
	//	minBufferTime: Number
	//		Time in milliseconds bwteen the playhead time and loaded time that
	//		will trigger the buffer. When buffer is triggered, video will pause
	//		until the bufferTime amount is buffered.
	//		Note: Should be a small number, greater than zero.
	minBufferTime:300,
	//
	// updateTime: Number
	//		How often, in milliseconds to get an update of the video position.
	updateTime: 100,
	//
	//  id: String?
	//		The id of this widget and the id of the SWF movie.
	id:"",
	//
	// isDebug: Boolean?
	//		Setting to true tells the SWF to output log messages to Firebug.
	isDebug: false, 
	//
	// percentDownloaded: read-only-Number
	//		The percentage the media has downloaded; from 0-100
	percentDownloaded:0,
	//
	// _flashObject: read-only-Object
	//	The dojox.embed object
	_flashObject:null,
	//
	// flashMedia: read-only-SWF 
	//		The SWF object. Methods are passed to this.
	flashMedia:null,
	//
	_initStatus: function(){
		// summary:
		//		Connect mediaStatus to the media.
		//
		this.status = "ready";
		dojo.connect(this, "onPosition", this, "_figureStatus");
		
	},
	
	//  ==============  //
	//  Player Getters  //
	//  ==============  //
	
	getTime: function(){
		// summary:
		// 		Returns the current time of the video
		//	Note:
		//		Consider the onPosition event, which returns
		//		the time at a set interval. Too many trips to 
		//		the SWF could impact performance.
		return this.flashMedia.getTime(); // Float
	},
	
	//  =============  //
	//  Player Events  //
	//  =============  //
	
	onLoad: function(/* SWF */ mov){
		// summary:
		// 		Fired when the SWF player has loaded
		// 		NOT when the video has loaded
		//
	},
	
	onDownloaded: function(/* Number */percent){
		// summary:
		//		Fires the amount of that the media has been 
		//		downloaded. Number, 0-100
	},
	
	onClick: function(/* Object */ evt){ 
		// summary:
		// 		TODO: Return x/y of click
		// 		Fires when the player is clicked
		// 		Could be used to toggle play/pause, or 
		// 		do an external activity, like opening a new
		//		window.
	},
	
	onSwfSized: function(/* Object */ data){
		// summary:
		// 		Fired on SWF resize, or when its
		// 		toggled between fullscreen.
	},
	
	onMetaData: function(/* Object */ data, /* Object */ evt){
		// summary:
		// 		The video properties. Width, height, duration, etc.
		// 		NOTE: 	if data is empty, this is an older FLV with no meta data.
		// 				Duration cannot be determined. In original FLVs, duration 
		//				could only be obtained with Flash Media Server.
		// 		NOTE: 	Older FLVs can still return width and height
		//				and will do so on a second event call
		this.duration = data.duration;
	},
	
	onPosition: function(/* Float */ time){
		// summary:
		//		The position of the playhead in seconds 
	},
	
	onStart: function(/* Object */ data){
		// summary:
		// 		Fires when video starts
		// 		Good for setting the play button to pause
		// 		during an autoPlay for example
	},
	
	onPlay: function(/* Object */ data){
		// summary:
		// 		Fires when video starts and resumes
	},
	
	onPause: function(/* Object */ data){
		// summary:
		// 		Fires when the pause button is clicked
	},
	
	onEnd: function(/* Object */ data){
		// summary:
		// 		Fires when video ends
		// 		Could be used to change pause button to play
		// 		or show a post video graphic, like YouTube
	},
	
	onStop: function(){
		// summary:
		// Fire when the Stop button is clicked
		// TODO: 	This is not hooked up yet and shouldn't
		//			fire.
	},
	
	onBuffer: function(/* Boolean */ isBuffering){
		// summary:
		//		Fires a boolean to tell if media
		//		is paused for buffering or if buffering
		//		has finished
		this.isBuffering = isBuffering;
	},
	
	onError: function(/* Object */ data, /* String */ url){
		// summary:
		// 		Fired when the player encounters an error
		// example:
		//		| console.warn("ERROR-"+data.type.toUpperCase()+":", 
		//		|		data.info.code, " - URL:", url);
		console.warn("ERROR-"+data.type.toUpperCase()+":", data.info.code, " - URL:", url);
	},
	
	onStatus: function(/* Object */data){
		// summary:
		// 		Simple status
	},
	
	onPlayerStatus: function(/* Object */data){
		// summary:
		// 		The status of the video from the SWF
		// 		playing, stopped, bufering, etc.
	},
	
	onResize: function(){
		
	},
	
	_figureStatus: function(){
		// summary:
		//		Calculate media status, based on playhead movement, and
		//		onStop and onStart events
		// TODO:
		//		Figure in real status from the media for more accurate results.
		//
		var pos = this.getTime();
		//console.log(pos, this.duration,  (pos>this.duration-.5), (this.duration && pos>this.duration-.5))
		
		if(this.status=="stopping"){
			// stop was fired, need to fake pos==0
			this.status = "stopped";
			this.onStop(this._eventFactory());
		
		}else if(this.status=="ending" && pos==this._prevPos){
			this.status = "ended";
			this.onEnd(this._eventFactory());
			
		}else if(this.duration && pos>this.duration-.5){
			this.status="ending"
		
		}else if(pos===0 ){//|| this.status == "stopped"
			if(this.status == "ready"){
				//never played	
			}else{
				//stopped
				this.status = "stopped";
				if(this._prevStatus != "stopped"){
					this.onStop(this._eventFactory());	
				}
			}
			
		}else{
			// pos > 0
			if(this.status == "ready"){
				//started
				this.status = "started";
				this.onStart(this._eventFactory());
				this.onPlay(this._eventFactory());
			
			}else if(this.isBuffering){
				this.status = "buffering";
			
			}else if(this.status == "started" || (this.status == "playing" &&  pos != this._prevPos)){
				this.status = "playing";
				//this.onPosition(this._eventFactory());
			
			}else if(!this.isStopped && this.status == "playing" && pos == this._prevPos){
				this.status = "paused";
				console.warn("pause", pos, this._prevPos)
				if(this.status != this._prevStatus){
					this.onPause(this._eventFactory());	
				}
			
			}else if((this.status == "paused" ||this.status == "stopped") && pos != this._prevPos){
				this.status = "started";
				this.onPlay(this._eventFactory());
			}
		}

		this._prevPos = pos;
		this._prevStatus = this.status;
		this.onStatus(this.status);
	
	
	},
	
	_eventFactory: function(){
		// summary:
		//		Creates a generic event object.
		//
		var evt = {
			//position:this._channel.position,
			//seconds:this.toSeconds(this._channel.position*.001),
			//percentPlayed:this._getPercent(),
			status:this.status
		}
		return evt; // Object
	},
	
	
	
	_sub: function(topic, method){
		// summary:
		// helper for subscribing to topics
		dojo.subscribe(this.id+"/"+topic, this, method);
	},
	
	_normalizeVolume: function(vol){
		// summary:
		//		Ensures volume is less than one
		//
		if(vol>1){
			while(vol>1){
				vol*=.1	
			}
		}
		return vol;
	},
	
	_normalizeUrl: function(_url){
		// summary:
		//		Checks that path is relative to HTML file or
		//		convertes it to an absolute path. 
		//
		
		console.log("  url:", _url);
		
		if(_url && (_url.toLowerCase().indexOf("http")<0 || _url.indexOf("/") == 0)){
			//
			// Appears to be a relative path. Attempt to  convert it to absolute, 
			// so it will better target the SWF.
			var loc = window.location.href.split("/");
			loc.pop();
			
			loc = loc.join("/")+"/";
			console.log("  loc:", loc);
			_url = loc+_url;
		}
		return _url;
	},
	
	destroy: function(){
		// summary:
		// 		destroys flash
		if(!this.flashMedia){
			this._cons.push(dojo.connect(this, "onLoad", this, "destroy"));	
			return;
		}
		dojo.forEach(this._subs, function(s){
			dojo.unsubscribe(s);								  
		});
		dojo.forEach(this._cons, function(c){
			dojo.disconnect(c);								  
		});
		this._flashObject.destroy();
		//dojo._destroyElement(this.flashDiv);
		
	}
});